package socks

import (
	"fmt"
	"io"
	"log"
	"net"
	"sync/atomic"
	"time"
)

var (
	g_connectId int32 = 1000
)

type PackData struct {
	Head interface{}
	Body []byte
}

type SocketConnection interface {
	SendData(avDatas []byte) bool //普通消息，需要组包，写入包头
	SendRawData(data []byte) bool // 发送原始消息，不需要组包，直接发送
	RemoteAddr() net.Addr
	GetId() int32
	Disconnect()
	GetData() interface{}
	SetData(usrData interface{})
}

type IPackHeader interface {
	ReadPack(reader io.Reader, conn SocketConnection) (pack *PackData) // 不成功返回空
	WritePack(writer io.Writer, datas []byte) bool                     // 发送普通包的时候用到
}

type MsgBody struct {
	MsgHead interface{}
	Datas   []byte
}

const (
	msg_normal = 0 // 0: 普通消息
	msg_rawMsg = 1 // 1: 原始消息，不用加包头
)

type sendMsg struct {
	msgType byte // 0: 普通消息  1: 原始消息，不用加包头
	datas   []byte
}

const (
	def_sock_buff_size = 1024 * 8
	is_show_log        = false
)

type socketConnection struct {
	id         int32
	isClose    atomic.Bool
	addr       net.Addr
	connection net.Conn
	userData   atomic.Value // 连接存数据的地方，可以存状态
	msgs       chan *sendMsg
}

func (c *socketConnection) GetData() any {
	return c.userData.Load()
}
func (c *socketConnection) SetData(usrData any) {
	c.userData.Store(usrData)
}

func (c *socketConnection) setConn(conn net.Conn) {
	c.connection = conn
	if conn != nil {
		c.addr = conn.RemoteAddr()
		c.isClose.Store(false)
	} else {
		c.isClose.Store(true)
	}
	fmt.Println("setconn: ", c.isClose.Load())
}

func (c *socketConnection) SendData(data []byte) (ret bool) {
	if c.isClose.Load() {
		fmt.Println("is closed: true")
		return false
	}

	bits := make([]byte, len(data)) // 这里要复制一份数据
	copy(bits, data)

	msg := &sendMsg{msg_normal, bits}
	select {
	case c.msgs <- msg:
		ret = true
	default:
		ret = false
	}

	return ret
}

func (c *socketConnection) SendRawData(data []byte) (ret bool) {
	if c.isClose.Load() {
		return false
	}

	bits := make([]byte, len(data)) // 这里要复制一份数据
	copy(bits, data)

	msg := &sendMsg{msg_rawMsg, bits}
	select {
	case c.msgs <- msg:
		ret = true
	default:
		ret = false
	}

	return true
}

func (c *socketConnection) RemoteAddr() net.Addr {
	return c.addr
}

func (c *socketConnection) GetId() int32 {
	return c.id
}

func (c *socketConnection) Disconnect() {
	if c.isClose.CompareAndSwap(false, true) {
		c.connection.Close()
		// 不能关闭，否则使用的时候会出错，让他自己释放
		// close(c.msgs)
		fmt.Println("disconnect ", getCallStack())
	}
}

type IMsgHandler interface {
	OnConnect(sock SocketConnection)
	OnDisconnect(sock SocketConnection)
	OnMessage(sock SocketConnection, msg *PackData)
}

type SockOptions struct {
	HeadHandler IPackHeader
	MsgHandler  IMsgHandler
}

func (opt *SockOptions) init() {
	if opt.MsgHandler == nil {
		panic("数据处理处理接口不能为空！！！")
	}
	if opt.HeadHandler == nil {
		opt.HeadHandler = NewDefaultHeadHandler(nil)
	}
}

// 内部使用的接口
type iConnHandler interface {
	procConnect(sock *socketConnection)
	procDisconnect(sock *socketConnection)
}

type sockContext struct {
	SockOptions
	myConnHandler iConnHandler // 内部使用的接口
}

func (sc *sockContext) process_connection(connection *socketConnection) {
	conn := connection.connection

	defer func() {
		connection.Disconnect()
		sc.myConnHandler.procDisconnect(connection)
		fmt.Println("sock closed!!!")
	}()

	sc.myConnHandler.procConnect(connection)

	go sc.proccess_packread(connection)

	for {
		select {
		case msg := <-connection.msgs:
			err := conn.SetWriteDeadline(time.Now().Add(30 * time.Second))
			if err != nil {
				log.Println("SetWriteDeadline: error, msg = ", err)
				break
			}
			if msg.msgType == msg_normal {
				if !sc.HeadHandler.WritePack(conn, msg.datas) {
					log.Println("WritePack: error")
					break
				}
			} else {
				if !writeBuffer(conn, msg.datas) {
					log.Println("writeBuffer: error")
					break
				}
			}
		default:
			if connection.isClose.Load() {
				break
			}
			time.Sleep(time.Millisecond * 10)
		}
	}
}

func (sc *sockContext) proccess_packread(sockConn *socketConnection) {
	for {
		pack := sc.HeadHandler.ReadPack(sockConn.connection, sockConn)
		if pack != nil {
			sc.MsgHandler.OnMessage(sockConn, pack)
		} else {
			break
		}
	}
}

func show_log(v ...any) {
	if is_show_log {
		fmt.Println(v...)
	}

}

func createSocketConnection(conn net.Conn) *socketConnection {
	lvConn := socketConnection{id: atomic.AddInt32(&g_connectId, 1), msgs: make(chan *sendMsg, 100)}
	lvConn.setConn(conn)
	return &lvConn
}
